<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div id="app"></div>

    <script>
        // 虚拟DOM-vnode数据对象  ==> 一个JS对象，且该属性可以基于属性生成对应的HTML结构
        let vnodes = [
            {
                tag: "div",
                // 记录的使用的模板语法
                attrs:{
                    "v-text":"msg"
                }
            },
            {
                tag: "div",
                attrs:{
                    "v-text":"info"
                }
            },
            {
                tag: "div",
                attrs:{
                    "v-text":"msg"
                }
            },
            {
                tag: "div",
                attrs:{
                    "v-text":"info"
                }
            }
        ];

        // 监视存储对象--将劫持数据变量名作为监视对应的变量，并在构建DOM时完成对应DOM的记录
        let watcher = {
            // msg:[……]
        };
        let _obj = {
            msg:"测试页面数据msg",
            info:"测试页面数据info"
        }
        // 构建类似于vue的数据仓库劫持对象
        let obj = {}
        for (let k in _obj) {
            Object.defineProperty(obj,k,{
                get(){
                    return _obj[k];
                },
                set(nv){
                    _obj[k] = nv;
                    // 当某个劫持变量发生数据变化，需要对该变量对应的DOM进行重新的功能调用和渲染操作
                    watcher[k].forEach(function(item){
                        // item.textContent = nv;
                        item.textContent = _obj[k];
                    });
                }
            })
        }

        // 基于vnode创建真实的HTML标签
        function createElement(vnode) {
            // 创建对象描述的html标签元素
            var dom = document.createElement(vnode.tag);
            // 判断当前虚拟DOM节点是否绑定了 指令语法 v-text
            if( vnode.attrs&&vnode.attrs["v-text"] ){
                // 通过 取值方式 获取指令 v-text 的对应变量名
                let k = vnode.attrs["v-text"];
                // 监控对象中是否存在 k 描述的变量对象的 数组
                if(watcher[k]){
                    // 如果存在，填充当前 DOM 作为新元素
                    watcher[k].push( dom )
                }else{
                    // 如果不存在，创建数组，并将DOM作为元素填充
                    watcher[k] = [ dom ]
                }

                // 基于 指令对应的仓库变量，完成功能执行
                dom.textContent = obj[k]
            }
            return dom;
        }

        // 通过循环将所有的虚拟DOM都创建成真实HTML元素，并写入页面
        let box = document.createDocumentFragment();
        for (let vnode of vnodes) {
            box.appendChild( createElement(vnode) )
        }
        let appDom = document.querySelector("#app");
        appDom.appendChild(box)

    </script>
</body>

</html>